﻿namespace PorteringManagement.Model
{
    using System;
    using System.Collections.Generic;
    using System.ComponentModel;
    using System.ComponentModel.DataAnnotations;
    using System.Linq;
    using PorteringManagement.RouteEngine;

    public class Itinerary
    {
        [Key]
        public int ItineraryID { get; set; }

        public int DeparturePortID { get; set; }

        public int ArrivalPortID { get; set; }

        [DisplayName("Nombre")]
        public string Name { get; set; }

        [DisplayName("Descripción")]
        public string Descripion { get; set; }

        public virtual DateTime? DepartureTime { get; set; }

        public virtual Port DeparturePort { get; set; }

        public virtual DateTime? ArrivalTime { get; set; }

        public virtual Port ArrivalPort { get; set; }

        public virtual ICollection<Journey> Journeys { get; set; }

        public static ICollection<Journey> CalculareMinPath(Port origin, IEnumerable<Port> ports, AnalysisType analysisType)
        {
            return CalculareMinPath(origin, ports, analysisType, PortRelation.GetAllByPorts(ports));
        }

        public static ICollection<Journey> CalculareMinPath(Port origin, IEnumerable<Port> ports, AnalysisType analysisType, IEnumerable<PortRelation> relations)
        {
            var result = new List<Journey>();
            var locations = new Dictionary<int, Location>();
            var portsDic = new Dictionary<string, Port>();
            var locationList = new List<Location>();
            var connections = new List<Connection>();

            foreach (var item in ports)
            {
                var loc = new Location { Identifier = item.PortID.ToString() };

                locations.Add(item.PortID, loc);
                locationList.Add(loc);
                portsDic.Add(loc.Identifier, item);
            }

            foreach (var item in relations)
            {
                Location locOrig = null;
                Location locDest = null;
                if (!locations.TryGetValue(item.OriginPort.PortID, out locOrig))
                {
                    locOrig = new Location { Identifier = item.OriginPort.PortID.ToString() };
                    locations[item.OriginPort.PortID] = locOrig;
                    locationList.Add(locOrig);
                    portsDic.Add(locOrig.Identifier, item.OriginPort);
                }

                if (!locations.TryGetValue(item.DestinationPort.PortID, out locDest))
                {
                    locDest = new Location { Identifier = item.DestinationPort.PortID.ToString() };
                    locations[item.DestinationPort.PortID] = locDest;
                    locationList.Add(locDest);
                    portsDic.Add(locDest.Identifier, item.DestinationPort);
                }

                var connection = new Connection(locOrig, locDest, item.GetWeight(analysisType));
                connections.Add(connection);
            }

            var engine = new Engine { Connections = connections, Locations = locationList };
            var minPaths = engine.CalculateMinCost(locations[origin.PortID]);
            var destination = ports.LastOrDefault();

            foreach (var connection in minPaths[locations[destination.PortID]].Connections)
            {
                result.Add(new Journey { DeparturePortID = int.Parse(connection.A.Identifier), ArrivalPortID = int.Parse(connection.B.Identifier) });
            }

            return result;
        }
    }
}
